﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Drawing;

namespace Pixysoft.Hooks
{
    public class VirtualKeyboard
    {
        Form register;

        UserActivityHook hook;

        public VirtualKeyboard()
        {
            hook = new UserActivityHook(true, true);
            this.hook.KeyDown += hook_KeyDown;
            this.hook.KeyPress += hook_KeyPress;
            this.hook.KeyUp += hook_KeyUp;
            this.hook.MouseActivity += hook_MouseActivity;
        }

        public VirtualKeyboard(Form form)
            : this()
        {
            Register(form);
        }

        ~VirtualKeyboard()
        {
            if (this.hook == null)
                return;

            this.hook.KeyDown -= hook_KeyDown;
            this.hook.KeyPress -= hook_KeyPress;
            this.hook.KeyUp -= hook_KeyUp;
            this.hook.MouseActivity -= hook_MouseActivity;
            this.hook.Stop();
            this.hook = null;
        }


        void hook_MouseActivity(object sender, MouseExEventArgs e)
        {
            if (register == null)
            {
            }
            else
            {
                Point location = e.Location;

                if (e.Button == MouseButtons.Left)
                {
                    Rectangle captionRect = new Rectangle(register.Location, new Size(register.Width, SystemInformation.CaptionHeight));
                    if (captionRect.Contains(location))
                    {
                        HooksNativeMethod.SetWindowLong(register.Handle, KeyboardConstaint.GWL_EXSTYLE,
                            (int)HooksNativeMethod.GetWindowLong(register.Handle, KeyboardConstaint.GWL_EXSTYLE) & (~KeyboardConstaint.WS_DISABLED));
                        HooksNativeMethod.SendMessage(register.Handle, KeyboardConstaint.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
                    }
                    else
                    {
                        HooksNativeMethod.SetWindowLong(register.Handle, KeyboardConstaint.GWL_EXSTYLE,
                            (int)HooksNativeMethod.GetWindowLong(register.Handle, KeyboardConstaint.GWL_EXSTYLE) | KeyboardConstaint.WS_DISABLED);
                    }
                }
            }

            if (MouseClick != null)
                MouseClick(sender, e);
        }

        void hook_KeyUp(object sender, KeyExEventArgs e)
        {
            if (this.KeyUp != null)
                KeyUp(sender, e);
        }

        void hook_KeyPress(object sender, KeyPressExEventArgs e)
        {
            if (this.KeyPress != null)
                KeyPress(sender, e);
        }

        void hook_KeyDown(object sender, KeyExEventArgs e)
        {
            if (this.KeyDown != null)
                KeyDown(sender, e);
        }


        public event MouseEventHandler MouseClick;

        public event KeyPressEventHandler KeyPress;

        public event KeyEventHandler KeyDown;

        public event KeyEventHandler KeyUp;

        public void Register(Form form)
        {
            this.register = form;
        }

        public void Unregister()
        {
            this.register = null;
        }


        public static bool IsKeyDown(Keys keycode)
        {
            short keyState = HooksNativeMethod.GetKeyState((int)keycode);
            return (keyState & 0xFF80) == 0XFF80;
        }

        public static bool IsSpecialKeyDown(Keys keycode)
        {
            short keyState = HooksNativeMethod.GetKeyState((int)keycode);
            return (keyState & 0x0001) == 0X0001;
        }

        public static void SendKeyDown(Keys keycode)
        {
            Input[] input = new Input[1];
            input[0].type = INPUT.KEYBOARD;
            input[0].keyboardInput.wVk = (short)keycode;
            input[0].keyboardInput.time = HooksNativeMethod.GetTickCount();

            if (HooksNativeMethod.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }

        public static void SendKeyUp(Keys keycode)
        {
            Input[] input = new Input[1];
            input[0].type = INPUT.KEYBOARD;
            input[0].keyboardInput.wVk = (short)keycode;
            input[0].keyboardInput.dwFlags = KeyboardConstaint.KEYEVENTF_KEYUP;
            input[0].keyboardInput.time = HooksNativeMethod.GetTickCount();

            if (HooksNativeMethod.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
    }
}
